package com.ioc.business.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ioc.business.base.domain.CustomerInfo;
import com.ioc.business.base.mapper.CustomerInfoMapper;
import com.ioc.business.order.domain.PlanArrivalOrder;
import com.ioc.business.order.domain.PlanArrivalOrderItem;
import com.ioc.business.order.domain.bo.plan.arrival.GlobalCustomerSetBo;
import com.ioc.business.order.domain.bo.plan.arrival.PlanArrivalOrderBo;
import com.ioc.business.order.domain.bo.plan.arrival.PlanArrivalOrderQueryBo;
import com.ioc.business.order.domain.bo.plan.arrival.item.PlanArrivalOrderItemBo;
import com.ioc.business.order.domain.dto.PlanArrivalOrderDto;
import com.ioc.business.order.mapper.PlanArrivalOrderItemMapper;
import com.ioc.business.order.mapper.PlanArrivalOrderMapper;
import com.ioc.business.order.service.IPlanArrivalOrderItemService;
import com.ioc.business.order.service.IPlanArrivalOrderService;
import com.ioc.business.order.vo.plan.arrival.PlanArrivalOrderImportVo;
import com.ioc.business.order.vo.plan.arrival.PlanArrivalOrderPageVo;
import com.ioc.business.order.vo.plan.arrival.PlanArrivalOrderVo;
import com.ioc.business.order.vo.plan.arrival.item.PlanArrivalOrderItemVo;
import com.ioc.common.constant.UserConstants;
import com.ioc.common.core.page.TableVo;
import com.ioc.common.exception.ServiceException;
import com.ioc.common.utils.CollectionUtils;
import com.ioc.common.utils.DateUtils;
import com.ioc.common.utils.SecurityUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 计划到货订单表 服务实现类
 * </p>
 *
 * @author WeiZhongRong
 * @since 2025-01-08
 */
@Service
@AllArgsConstructor
public class PlanArrivalOrderServiceImpl extends ServiceImpl<PlanArrivalOrderMapper, PlanArrivalOrder> implements IPlanArrivalOrderService {


    private final IPlanArrivalOrderItemService planArrivalOrderItemService;

    private final CustomerInfoMapper customerInfoMapper;

    private final PlanArrivalOrderItemMapper planArrivalOrderItemMapper;

    @Override
    public TableVo<PlanArrivalOrder, PlanArrivalOrderPageVo> selectPlanArrivalOrderPageList(PlanArrivalOrderQueryBo queryBo) {
        List<PlanArrivalOrder> result = baseMapper
                .queryPageList(queryBo);
        List<PlanArrivalOrderPageVo> pageVos = new ArrayList<>(result.size());
        if (CollectionUtil.isNotEmpty(result)) {
            pageVos = buildPageVos(result);
        }
        return new TableVo<>(result, pageVos);
    }

    private List<PlanArrivalOrderPageVo> buildPageVos(List<PlanArrivalOrder> records) {
        return records.stream().map(record -> {
            PlanArrivalOrderPageVo vo = new PlanArrivalOrderPageVo();
            BeanUtils.copyProperties(record, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public PlanArrivalOrderVo selectPlanArrivalOrderById(Long planArrivalOrderId) {
        PlanArrivalOrder planArrivalOrder = getById(planArrivalOrderId);
        if (ObjectUtil.isNotEmpty(planArrivalOrder)) {
            PlanArrivalOrderVo planArrivalOrderVo = new PlanArrivalOrderVo();
            BeanUtils.copyProperties(planArrivalOrder, planArrivalOrderVo);
            List<PlanArrivalOrderItem> orderItemList = planArrivalOrderItemService.seletByPlanArrivalOrderId(planArrivalOrderId);
            if (CollectionUtil.isNotEmpty(orderItemList)) {
                List<PlanArrivalOrderItemVo> planArrivalOrderItemVos = BeanUtil.copyToList(orderItemList, PlanArrivalOrderItemVo.class);
                planArrivalOrderVo.setOrderItemList(planArrivalOrderItemVos);
            }
            return planArrivalOrderVo;
        }
        return null;
    }

    /**
     * 新增收货订单
     *
     * @param bo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean addPlanArrivalOrder(PlanArrivalOrderBo bo) {
        PlanArrivalOrder planArrivalOrder = new PlanArrivalOrder();
        BeanUtils.copyProperties(bo, planArrivalOrder);
        Date date = new Date();
        String username = SecurityUtils.getUsername();
        planArrivalOrder.setCreateBy(username);
        planArrivalOrder.setCreateTime(date);
        planArrivalOrder.setUpdateBy(username);
        planArrivalOrder.setUpdateTime(date);
        planArrivalOrder.setDelFlag(UserConstants.DEL_FLAG_NORMAL);
        List<PlanArrivalOrderItemBo> orderItemList = bo.getOrderItemList();
        boolean save = save(planArrivalOrder);
        if (CollectionUtil.isNotEmpty(orderItemList)) {
            BigDecimal bigDecimal = CollectionUtils.computeMapperTotal(orderItemList, PlanArrivalOrderItemBo::getOrderNum);
            planArrivalOrder.setTotalOrderNum(bigDecimal.toEngineeringString());
            buildSaveOrderItemList(planArrivalOrder, orderItemList);
            List<PlanArrivalOrderItem> saveItemList = buildSaveOrderItemList(planArrivalOrder, orderItemList);
            planArrivalOrderItemService.saveBatch(saveItemList);
        }
        return save;
    }

    private List<PlanArrivalOrderItem> buildSaveOrderItemList(PlanArrivalOrder planArrivalOrder, List<PlanArrivalOrderItemBo> orderItemList) {
        return orderItemList.stream().map(orderItemVo -> {
            PlanArrivalOrderItem planArrivalOrderItem = new PlanArrivalOrderItem();
            planArrivalOrderItem.setPlanArrivalOrderId(planArrivalOrder.getPlanArrivalOrderId());
            planArrivalOrderItem.setCustomerId(orderItemVo.getCustomerId());
            planArrivalOrderItem.setCustomerName(orderItemVo.getCustomerName());
            planArrivalOrderItem.setOrderNum(StrUtil.isNotBlank(orderItemVo.getOrderNum()) ? orderItemVo.getOrderNum() : "0");
            planArrivalOrderItem.setCreateBy(planArrivalOrder.getCreateBy());
            planArrivalOrderItem.setCreateTime(planArrivalOrder.getCreateTime());
            planArrivalOrderItem.setUpdateBy(planArrivalOrder.getUpdateBy());
            planArrivalOrderItem.setUpdateTime(planArrivalOrder.getUpdateTime());
            planArrivalOrderItem.setDelFlag(UserConstants.DEL_FLAG_NORMAL);
            return planArrivalOrderItem;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updatePlanArrivalOrder(PlanArrivalOrderBo bo) {
        PlanArrivalOrder planArrivalOrder = new PlanArrivalOrder();
        BeanUtils.copyProperties(bo, planArrivalOrder);
        planArrivalOrder.setUpdateBy(SecurityUtils.getUsername());
        planArrivalOrder.setUpdateTime(planArrivalOrder.getCreateTime());

        Long planArrivalOrderId = bo.getPlanArrivalOrderId();
        List<Long> planArrivalOrderIdList = new ArrayList<>();
        planArrivalOrderIdList.add(planArrivalOrderId);
        planArrivalOrderItemService.deleteByPlanArrivalOrderIdList(planArrivalOrderIdList);
        List<PlanArrivalOrderItemBo> orderItemList = bo.getOrderItemList();
        if (CollectionUtil.isNotEmpty(orderItemList)) {
            BigDecimal bigDecimal = CollectionUtils.computeMapperTotal(orderItemList, PlanArrivalOrderItemBo::getOrderNum);
            planArrivalOrder.setTotalOrderNum(bigDecimal.toEngineeringString());
            buildSaveOrderItemList(planArrivalOrder, orderItemList);
            List<PlanArrivalOrderItem> saveItemList = buildSaveOrderItemList(planArrivalOrder, orderItemList);
            planArrivalOrderItemService.saveBatch(saveItemList);
        }
        return updateById(planArrivalOrder);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removePlanArrivalOrder(List<Long> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return false;
        }
        List<PlanArrivalOrder> updateList = idList.stream().map(id -> {
            PlanArrivalOrder planArrivalOrder = new PlanArrivalOrder();
            planArrivalOrder.setPlanArrivalOrderId(id);
            planArrivalOrder.setDelFlag(UserConstants.DEL_FLAG_REMOVED);
            return planArrivalOrder;
        }).collect(Collectors.toList());
        return updateBatchById(updateList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean setCustomerInfo(GlobalCustomerSetBo bo) {
        List<PlanArrivalOrder> queryList = new LambdaQueryChainWrapper<>(baseMapper)
                .in(CollectionUtil.isNotEmpty(bo.getPlanArrivalOrderIdList()), PlanArrivalOrder::getPlanArrivalOrderId, bo.getPlanArrivalOrderIdList())
                .eq(PlanArrivalOrder::getDelFlag, UserConstants.DEL_FLAG_NORMAL)
                .list();
        if (CollectionUtil.isEmpty(queryList)) {
            return false;
        }
        List<Long> planArrivalOrderIdList = queryList.stream().map(PlanArrivalOrder::getPlanArrivalOrderId).collect(Collectors.toList());
        planArrivalOrderItemService.deleteByPlanArrivalOrderIdList(planArrivalOrderIdList);
        List<PlanArrivalOrderItem> saveItemList = new ArrayList<>();
        for (PlanArrivalOrder planArrivalOrder : queryList) {
            saveItemList.addAll(buildSaveOrderItemList(planArrivalOrder, bo.getCustomerInfoList()));
        }
        planArrivalOrderItemService.saveBatch(saveItemList);
        Map<Long, List<PlanArrivalOrderItem>> planArrivalOrderIdItemListMap =
                saveItemList.stream().collect(Collectors.groupingBy(PlanArrivalOrderItem::getPlanArrivalOrderId));

        queryList.forEach(query -> {
            Long planArrivalOrderId = query.getPlanArrivalOrderId();
            List<PlanArrivalOrderItem> itemList =
                    planArrivalOrderIdItemListMap.getOrDefault(planArrivalOrderId, new ArrayList<>(0));
            query.setTotalOrderNum(CollectionUtils.computeMapperTotal(itemList, PlanArrivalOrderItem::getOrderNum).toEngineeringString());
            query.setUpdateBy(SecurityUtils.getUsername());
            query.setUpdateTime(new Date());
        });
        return updateBatchById(queryList);
    }

    @Override
    public boolean checkArrivalOrderDate(Long planArrivalOrderId, Date arrivalOrderDate) {
        PlanArrivalOrder queryOne = new LambdaQueryChainWrapper<>(baseMapper)
                .eq(PlanArrivalOrder::getArrivalOrderDate, arrivalOrderDate)
                .eq(PlanArrivalOrder::getDelFlag, UserConstants.DEL_FLAG_NORMAL)
                .last("LIMIT 1").one();
        boolean add = ObjectUtil.isEmpty(planArrivalOrderId) && ObjectUtil.isNotEmpty(queryOne);
        boolean update = ObjectUtil.isNotEmpty(planArrivalOrderId) &&
                ObjectUtil.isNotEmpty(queryOne) && !planArrivalOrderId.equals(queryOne.getPlanArrivalOrderId());
        return add || update;
    }

    @Override
    public List<String> getCustomerNameOptions(String date) {
        Date arrivalOrderDate = null;
        try {
            arrivalOrderDate = DateUtil.parse(date);
        } catch (Exception e) {
            throw new ServiceException("计划到货日期格式不正确!");
        }
        PlanArrivalOrder queryOne = new LambdaQueryChainWrapper<>(baseMapper)
                .eq(PlanArrivalOrder::getArrivalOrderDate, arrivalOrderDate)
                .eq(PlanArrivalOrder::getDelFlag, UserConstants.DEL_FLAG_NORMAL)
                .last("LIMIT 1").one();
        if (ObjectUtil.isEmpty(queryOne)) {
            new ArrayList<>(0);
        }
        List<PlanArrivalOrderItem> list = new LambdaQueryChainWrapper<>(planArrivalOrderItemMapper)
                .eq(PlanArrivalOrderItem::getPlanArrivalOrderId, queryOne.getPlanArrivalOrderId())
                .eq(PlanArrivalOrderItem::getDelFlag, UserConstants.DEL_FLAG_NORMAL)
                .list();

        if (CollectionUtil.isEmpty(list)) {
            new ArrayList<>(0);
        }
        return list.stream().map(PlanArrivalOrderItem::getCustomerName).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class) // 声明该方法为事务性方法，发生异常时回滚事务
    @Override // 重写父类方法
    public void importPlanArrivalOrder(List<PlanArrivalOrderImportVo> voList) { // 导入计划到达订单的方法
        List<PlanArrivalOrderDto> planArrivalOrderDtoList = verifyImportData(voList); // 验证导入数据并返回 DTO 列表

        Map<String, List<PlanArrivalOrderDto>> dateStrDtoListMap = // 按到达订单日期分组 DTO 列表
                planArrivalOrderDtoList.stream().collect(Collectors.groupingBy(PlanArrivalOrderDto::getArrivalOrderDate));

        List<PlanArrivalOrder> queryOrderList = // 查询已存在的订单列表
                baseMapper.selectListByArrivalOrderDates(new ArrayList<>(dateStrDtoListMap.keySet()));
        String username = SecurityUtils.getUsername(); // 获取当前用户名
        Date date = new Date(); // 获取当前日期
        List<String> updateDateList = new ArrayList<>(dateStrDtoListMap.size()); // 存储需要更新的日期列表
        List<String> saveDateList = new ArrayList<>(dateStrDtoListMap.size()); // 存储需要保存的日期列表
        List<PlanArrivalOrderItem> saveOrderItemList = new ArrayList<>(voList.size()); // 存储待保存的订单项列表
        if (CollectionUtil.isNotEmpty(queryOrderList)) { // 如果查询到已有订单
            List<Long> planArrivalOrderIdList = queryOrderList.stream().map(PlanArrivalOrder::getPlanArrivalOrderId).collect(Collectors.toList()); // 获取订单 ID 列表
            planArrivalOrderItemService.deleteByPlanArrivalOrderIdList(planArrivalOrderIdList); // 删除对应订单的订单项
            Map<String, PlanArrivalOrder> queryDateOrderMap = queryOrderList.stream().collect(Collectors.toMap(queryOrder -> // 将订单按日期映射为键值对
                    DateUtil.format(queryOrder.getArrivalOrderDate(), DateUtils.YYYY_MM_DD), queryOrder -> queryOrder));
            for (String dateStr : dateStrDtoListMap.keySet()) { // 遍历日期字符串
                PlanArrivalOrder planArrivalOrder = queryDateOrderMap.getOrDefault(dateStr, null); // 获取对应日期的订单
                if (ObjectUtil.isNotEmpty(planArrivalOrder)) { // 如果订单存在
                    List<PlanArrivalOrderDto> orderDtoList = dateStrDtoListMap.getOrDefault(dateStr, new ArrayList<>(0)); // 获取对应的 DTO 列表
                    if (CollectionUtil.isNotEmpty(orderDtoList)) { // 如果 DTO 列表不为空
                        orderDtoList.forEach(orderDto -> { // 遍历订单 DTO 列表
                            orderDto.setPlanArrivalOrderId(planArrivalOrder.getPlanArrivalOrderId()); // 设置订单 ID
                        });
                        dateStrDtoListMap.put(dateStr, orderDtoList); // 更新日期对应的 DTO 列表
                    }
                    updateDateList.add(dateStr); // 添加到更新日期列表
                } else {
                    saveDateList.add(dateStr); // 添加到保存日期列表
                }
            }
        }
        if (CollectionUtil.isNotEmpty(updateDateList)) { // 如果有需要更新的日期
            List<PlanArrivalOrder> updateOrderList = buildOrderList(false, updateDateList, dateStrDtoListMap, username, date); // 构建更新订单列表
            updateBatchById(updateOrderList); // 批量更新订单
            List<PlanArrivalOrderItem> updateOrderItemList = buildOrderItemList(true, dateStrDtoListMap, updateOrderList, username, date); // 构建更新订单项列表
            saveOrderItemList.addAll(updateOrderItemList); // 添加到保存的订单项列表
        }

        if (CollectionUtil.isNotEmpty(saveDateList)) { // 如果有需要保存的日期
            List<PlanArrivalOrder> saveOrderList = buildOrderList(true, saveDateList, dateStrDtoListMap, username, date); // 构建保存订单列表
            saveBatch(saveOrderList); // 批量保存订单
            List<PlanArrivalOrderItem> saveItemList = buildOrderItemList(true, dateStrDtoListMap, saveOrderList, username, date); // 构建保存订单项列表
            saveOrderItemList.addAll(saveItemList); // 添加到保存的订单项列表

        }

        if (CollectionUtil.isNotEmpty(saveOrderItemList)) { // 如果有需要保存的订单项
            planArrivalOrderItemService.saveBatch(saveOrderItemList); // 批量保存订单项
        }
    }

    public List<PlanArrivalOrder> buildOrderList(boolean save, List<String> dateStrList, Map<String, List<PlanArrivalOrderDto>> dateStrListMap, String username, Date date) {
        return dateStrList.stream().map(dateStr -> {
            PlanArrivalOrder planArrivalOrder = new PlanArrivalOrder();
            planArrivalOrder.setArrivalOrderDate(DateUtil.parse(dateStr));
            List<PlanArrivalOrderDto> planArrivalOrderDtos = dateStrListMap.getOrDefault(dateStr, new ArrayList<>(0));
            BigDecimal totalOrderNum = CollectionUtils.computeMapperTotal(planArrivalOrderDtos, PlanArrivalOrderDto::getOrderNum);
            planArrivalOrder.setTotalOrderNum(totalOrderNum.toEngineeringString());
            if (save) {
                planArrivalOrder.setCreateBy(username);
                planArrivalOrder.setCreateTime(date);
                planArrivalOrder.setDelFlag(UserConstants.DEL_FLAG_NORMAL);
            } else {
                PlanArrivalOrderDto planArrivalOrderDto = planArrivalOrderDtos.stream().findFirst().orElse(null);
                if (ObjectUtil.isNotEmpty(planArrivalOrderDto)) {
                    planArrivalOrder.setPlanArrivalOrderId(planArrivalOrderDto.getPlanArrivalOrderId());
                }
            }
            planArrivalOrder.setUpdateBy(username);
            planArrivalOrder.setUpdateTime(date);
            return planArrivalOrder;
        }).collect(Collectors.toList());
    }

    public List<PlanArrivalOrderItem> buildOrderItemList(boolean save,
                                                         Map<String, List<PlanArrivalOrderDto>> dateStrDtoListMap,
                                                         List<PlanArrivalOrder> saveOrderList, String username, Date date) {

        List<PlanArrivalOrderItem> planArrivalOrderItemList = new ArrayList<>();
        for (PlanArrivalOrder planArrivalOrder : saveOrderList) {
            String arrivalOrderDateStr = DateUtil.format(planArrivalOrder.getArrivalOrderDate(), DateUtils.YYYY_MM_DD);
            List<PlanArrivalOrderDto> planArrivalOrderDtoList = dateStrDtoListMap.getOrDefault(arrivalOrderDateStr, new ArrayList<>(0));
            if (CollectionUtil.isEmpty(planArrivalOrderDtoList)) {
                continue;
            }
            planArrivalOrderItemList.addAll(buildOrderItemList(save, planArrivalOrder.getPlanArrivalOrderId(), planArrivalOrderDtoList, username, date));
        }

        return planArrivalOrderItemList;
    }

    public List<PlanArrivalOrderItem> buildOrderItemList(boolean save, Long planArrivalOrderId, List<PlanArrivalOrderDto> planArrivalOrderDtoList, String username, Date date) {
        if (CollectionUtil.isEmpty(planArrivalOrderDtoList)) {
            return new ArrayList<>(0);
        }
        return planArrivalOrderDtoList.stream().map(planArrivalOrderDto -> {
            PlanArrivalOrderItem planArrivalOrderItem = new PlanArrivalOrderItem();
            BeanUtils.copyProperties(planArrivalOrderDto, planArrivalOrderItem);
            planArrivalOrderItem.setPlanArrivalOrderId(planArrivalOrderId);
            if (save) {
                planArrivalOrderItem.setCreateBy(username);
                planArrivalOrderItem.setCreateTime(date);
                planArrivalOrderItem.setDelFlag(UserConstants.DEL_FLAG_NORMAL);
            }
            planArrivalOrderItem.setUpdateBy(username);
            planArrivalOrderItem.setUpdateTime(date);
            return planArrivalOrderItem;
        }).collect(Collectors.toList());
    }


    private List<PlanArrivalOrderDto> verifyImportData(List<PlanArrivalOrderImportVo> voList) {
        if (CollectionUtil.isEmpty(voList)) {
            throw new ServiceException("导入数据不能为空");
        }
        List<PlanArrivalOrderDto> planArrivalOrderList = new ArrayList<>(voList.size());
        List<CustomerInfo> list = new LambdaQueryChainWrapper<>(customerInfoMapper)
                .eq(CustomerInfo::getDelFlag, UserConstants.DEL_FLAG_NORMAL)
                .list();
        Map<String, Long> customerNameIdMapMap = CustomerInfo.toNameIdMap(list);

        for (PlanArrivalOrderImportVo planArrivalOrderImportVo : voList) {
            PlanArrivalOrderDto planArrivalOrderDto = new PlanArrivalOrderDto();
            BeanUtils.copyProperties(planArrivalOrderImportVo, planArrivalOrderDto);
            verifyField(planArrivalOrderDto, planArrivalOrderImportVo, customerNameIdMapMap);
            planArrivalOrderList.add(planArrivalOrderDto);
        }
        return planArrivalOrderList;
    }

    private void verifyField(PlanArrivalOrderDto planArrivalOrderDto,
                             PlanArrivalOrderImportVo planArrivalOrderImportVo,
                             Map<String, Long> customerNameIdMapMap) {
        String arrivalOrderDateStr = planArrivalOrderImportVo.getArrivalOrderDate();
        if (StrUtil.isBlank(arrivalOrderDateStr)) {
            throw new ServiceException("计划到货日期不能为空!");
        }
        Date arrivalOrderDate = null;
        try {
            arrivalOrderDate = DateUtil.parse(arrivalOrderDateStr);
        } catch (Exception e) {
            throw new ServiceException("计划到货日期格式不正确!");
        }
        planArrivalOrderDto.setArrivalOrderDate(DateUtil.format(arrivalOrderDate, DateUtils.YYYY_MM_DD));

        String customerName = planArrivalOrderImportVo.getCustomerName();
        if (StrUtil.isBlank(customerName)) {
            throw new ServiceException("客户名称不能为空!");
        }
        Long customerId = customerNameIdMapMap.getOrDefault(customerName, null);
        if (ObjectUtil.isEmpty(customerId)) {
            throw new ServiceException("客户名称【" + customerName + "】不存在!");
        }
        planArrivalOrderDto.setCustomerId(customerId);

        if (StrUtil.isBlank(planArrivalOrderImportVo.getOrderNum())) {
            throw new ServiceException("订单数不能为空!");
        }
    }
}
